//FAS低代码开发平台
//变更日志插件: 针对CUD操作记录变更日志，其中新增、修改的克隆TRecord逻辑是避免状态机插件【保存后事件】影响返给前端的TRecord内容
//新增：
//    1、前端NewTRecord A传入后【BeforeExecuteSQL】做初次变更比较（没有OldValue），为A生成ChangeSet供状态机【保存前事件】Action脚本使用
//    2、数据落盘后【Finish】，从DB中取出最新NewTRecord B（获取DB默认值），克隆NewTRecord C，将B传入插件，再次做变更比较。
//       此时生成的变更为包含状态机脚本更新后的最新变更，直接生成大数据日志，而后执行状态机的【保存后事件】
//    3、将C返回给前端。
//修改：
//    1、前端NewTRecord A传入后【BeforeExecuteSQL】，获取DB中的OldRecord，做变更比较，将NewTRecord A,OldValue传入供状态机【保存前事件】Action脚本使用
//    2、状态机【保存前事件】执行完毕后（A的ChangeSet已包含最新变更），克隆NewTRecord B，
//       数据落盘后【Finish】，将A传入变更日志插件中，直接生成大数据日志。而后执行状态机的【保存后事件】
//    3、将最新的时间戳赋值给B后返回前端。
//删除：
//    1、由于删除不走状态机逻辑，故在【BeforeExecuteSQL】时，变更日志插件中生成TRecord实例，只记录主键id变更，放到上下文中
//    2、数据落盘后【Finish】，在上下文中拿到生成的TRecord实例，生成大数据日志
//    3、删除不向前端返回数据
//===============================================================================
//变更历史纪录
//日期			版本	修改人	描述
//===============================================================================

using System;
using System.Collections.Generic;
using System.Linq;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.DataAccess.Common;
using T.FAS.Runtime.Metadata.Entity.DataModel;
using T.FAS.Runtime.Metadata.Client;
using T.FAS.Runtime.Metadata.SPI;
using T.ServiceComponent.Log.SPI;

namespace T.FAS.Runtime.DataAccess.Engine
{

    /// <summary>
    /// 修改的变更日志
    /// </summary>
    public class UpdateChangeLog : AbstractChangeLog
    {
        private IMetaDataClientService metaDataClientService = MetaDataClientService.GetInstance();
        TRecordPKComparer recordPKComparer = new TRecordPKComparer();

        /// <summary>
        /// 记录修改类型的变更日志
        /// </summary>
        /// <param name="changeLogContext"></param>
        /// <returns></returns>
        [Obsolete("已弃用")]
        public override TChangeLog LogChange(ChangeLogContext changeLogContext)
        {
            if (changeLogContext.CurrentData == null || changeLogContext.PrevData == null || changeLogContext.CompositeDataObject == null)
                return null;
            TChangeLog changeSetTemplate = base.CreateDataChangeSet(changeLogContext);
            changeSetTemplate.ModifyTime = DACContextHelper.GetTimestamp(); //新增时间的时间戳从线程上下文中获取
            ChangeSetTemplate = changeSetTemplate;  //暂存ChangeSet基本信息模板

            var changeSets = GetUpdateChangeLog(changeLogContext.CompositeDataObject.RootCompositeNodeObject
                                                , new List<TRecord> { changeLogContext.CurrentData }
                                                , new List<TRecord> { changeLogContext.PrevData }
                                                , out bool isChanged);
            var result = changeSets.FirstOrDefault();
            //比较主节点的TRecord是否有状态变更
            var stateChangedLogs = GetStateChanged(changeLogContext.CompositeDataObject, changeLogContext.PrevData, changeLogContext.CurrentData);
            if (changeSets != null && changeSets.Count > 0)
            {
                if (stateChangedLogs.Count > 0)
                {
                    var stateChangedLog = stateChangedLogs.FirstOrDefault();
                    result.OldStateCode = stateChangedLog.OldStateCode;
                    result.OldStateName = stateChangedLog.OldStateName;
                    result.NewStateCode = stateChangedLog.NewStateCode;
                    result.NewStateName = stateChangedLog.NewStateName;
                }
            }
            return isChanged ? (result.ChangeDatas != null && result.ChangeDatas.Count > 0 ? result : null) : null;
        }

        /// <summary>
        /// 记录大数据修改类型的变更日志
        /// </summary>
        /// <param name="changeLogContext"></param>
        /// <returns></returns>
        [Obsolete("已弃用")]
        public override DataChangeLog LogBigDataChangeLog(ChangeLogContext changeLogContext)
        {
            if (changeLogContext.CurrentData == null || changeLogContext.PrevData == null || changeLogContext.CompositeDataObject == null)
                return null;
            DataChangeLog dataChangeLog = null;
            var changeItem = GetBigDataUpdateChangeLog(changeLogContext.CompositeDataObject.RootCompositeNodeObject
                                                , new List<TRecord> { changeLogContext.CurrentData }
                                                , new List<TRecord> { changeLogContext.PrevData });
            //比较主节点的TRecord是否有状态变更
            var stateChangedLogs = GetStateChanged(changeLogContext.CompositeDataObject, changeLogContext.PrevData, changeLogContext.CurrentData);
            if (changeItem != null && changeItem.Count > 0)
            {
                dataChangeLog = base.CreateNewBigDataChangeLog(changeLogContext);
                dataChangeLog.FillDefaultField(changeLogContext.CurrentData);   //填充最后修改人 最后修改时间
                dataChangeLog.CreateTime = DACContextHelper.GetTimestamp(); //新增时间的时间戳从线程上下文中获取
                dataChangeLog.Datas = changeItem;

                if (stateChangedLogs.Count > 0)
                {
                    var stateChangedLog = stateChangedLogs.FirstOrDefault();
                    dataChangeLog.Ext11 = stateChangedLog.OldStateCode;
                    dataChangeLog.Ext12 = stateChangedLog.OldStateName;
                    dataChangeLog.Ext13 = stateChangedLog.NewStateCode;
                    dataChangeLog.Ext14 = stateChangedLog.NewStateName;
                }
            }
            return dataChangeLog;
        }

        /// <summary>
        /// 最新的Update变更日志
        /// </summary>
        /// <param name="changeLogContext"></param>
        /// <returns></returns>
        public override TRecord LogChangeSet(ChangeLogContext changeLogContext)
        {
            if (changeLogContext.CurrentData == null || changeLogContext.PrevData == null || changeLogContext.CompositeDataObject == null)
                return null;
            InitBasicChangeInfo();
            //BasicChangeInfo.ModifyTime = DACContextHelper.GetTimestamp(); //新增时间的时间戳从线程上下文中获取;

            ChangeLogControlContext controlContext = InitChangeLogControlContext(changeLogContext);
            GetUpdateChangeSet(changeLogContext.CompositeDataObject.RootCompositeNodeObject
                                                 , new List<TRecord> { changeLogContext.CurrentData }
                                                 , new List<TRecord> { changeLogContext.PrevData }
                                                 , out bool isChanged
                                                 , controlContext);
            if (isChanged)
            {
                changeLogContext.CurrentData.ChangeType = TRecordChangeType.Update;
            }
            //比较主节点的TRecord是否有状态变更
            var stateChangedLogs = GetStateChanged(changeLogContext.CompositeDataObject, changeLogContext.PrevData, changeLogContext.CurrentData);
            if (stateChangedLogs.Count > 0)
            {
                foreach (var log in stateChangedLogs)
                {
                    //为TRecord状态字段赋值，方便后续SetValue时，不丢失列的BusinessType
                    if (changeLogContext.CurrentData.StateColumnNames == null)
                        changeLogContext.CurrentData.StateColumnNames = new List<string>();
                    changeLogContext.CurrentData.StateColumnNames.Add(log.StateColKey);
                    var StateChangeItem = changeLogContext.CurrentData.ChangeSet.ChangeSetItems.FirstOrDefault(item => item.ColumnCode == log.StateColKey);
                    StateChangeItem.BusinessType = BusinessType.State;
                    StateChangeItem.InitValue = log.OldStateCode;
                    StateChangeItem.InitDisplayName = log.OldStateName;
                    //StateChangeItem.OldValue = log.OldStateCode;
                    StateChangeItem.OldDisplayValue = log.OldStateName;
                    //StateChangeItem.NewValue = log.NewStateCode;
                    StateChangeItem.NewDisplayValue = log.NewStateName;
                }
            }
            return changeLogContext.CurrentData;
        }

        #region 最新变更日志方法
        /// <summary>
        /// 填充TRecord的变更日志ChangeSet，归并新旧TRecord
        /// **将旧Record合并到New Record是否会有问题，列表长度变了 索引会变（旧的变更Append）
        /// </summary>
        /// <param name="cno"></param>
        /// <param name="newRecords"></param>
        /// <param name="oldRecords"></param>
        /// <param name="isChanged"></param>
        /// <param name="parentNewRecord">父级TRecord，归并record时，在父级TRecord中处理（追加）</param>
        /// <param name="depth"></param>
        private void GetUpdateChangeSet(CompositeNodeObject cno, List<TRecord> newRecords, List<TRecord> oldRecords, out bool isChanged, ChangeLogControlContext controlContext, TRecord parentNewRecord = null, int depth = 0)
        {
            try
            {
                isChanged = false;
                var pkEle = cno.GetPKElement();
                var pkColName = cno.GetPKColumn().ColumnName;
                var normalEle = cno.Elements.Where(e => e.ElementType == ElementType.Normal).ToList();
                //bool IsRecordChanged = false;                       //record是否有变更，主要是给二三级用

                //顶级节点校验Record是否为同一条TRecord
                if (cno.IsRootObject)
                {
                    if (newRecords.Count * oldRecords.Count == 1)
                    {
                        var newPk = PreprocessField(newRecords.FirstOrDefault()?.GetValue(pkEle));
                        var oldPk = PreprocessField(oldRecords.FirstOrDefault()?.GetValue(pkEle));
                        if (newPk == null || oldPk == null)
                            throw new FasException(DataAccessErrorCode.PlugIn.ChangeLog.Error, string.Format(CommonStringClassEngine.UpdateChangeLog_GetUpdateChangeSet));
                        else if (!FieldCompare(newPk, oldPk, pkEle.DataType))
                        {
                            throw new FasException(DataAccessErrorCode.PlugIn.ChangeLog.Error, string.Format(CommonStringClassEngine.UpdateChangeLog_GetUpdateChangeSet1));
                        }
                    }
                }

                List<TRecord> dropRecords = null;                   //需要drop的记录
                List<TRecord> addRecords = null;                    //需要add的记录
                List<object> needCompareRecordIdentifiers = null;   //需要比较的记录的主键

                InitRecord(newRecords, cno);
                InitRecord(oldRecords, cno);

                dropRecords = oldRecords?.Except(newRecords, recordPKComparer).ToList();            //一定要指定Comparer
                addRecords = newRecords.Except(oldRecords, recordPKComparer).ToList();              //一定要指定Comparer

                //兼容前端传入Delete ChangeSet的TRecord
                List<TRecord> recordWithDeleteFlag = newRecords?.Where(r => r.ChangeType == TRecordChangeType.Delete || (r.ChangeSet != null && r.ChangeSet.ChangeType == TRecordChangeType.Delete)).ToList();
                if (recordWithDeleteFlag != null && recordWithDeleteFlag.Count > 0 && dropRecords != null)
                {
                    dropRecords.AddRange(recordWithDeleteFlag);
                }

                var needCompareRecords = oldRecords.Except(dropRecords, recordPKComparer)?.ToList();
                needCompareRecordIdentifiers = needCompareRecords?.Select(t => t.GetValue(pkColName)).ToList();

                if (needCompareRecordIdentifiers != null)
                {
                    foreach (var pk in needCompareRecordIdentifiers)
                    {
                        var currentPkChangedFlag = false;
                        var newRecord = newRecords.FirstOrDefault(r => FieldCompare(r.GetValue(pkColName), pk, pkEle.DataType));
                        var oldRecord = oldRecords.FirstOrDefault(r => FieldCompare(r.GetValue(pkColName), pk, pkEle.DataType));
                        //比较当前节点字段变更
                        if (currentPkChangedFlag = CompareAndSetChange(cno, newRecord, oldRecord, controlContext, depth))
                        {
                            newRecord.ChangeType = TRecordChangeType.Update;
                        }
                        //需要递归比较变更
                        if (cno.ChildCompositeNodeObjects != null)
                        {
                            foreach (var childCNO in cno.ChildCompositeNodeObjects)
                            {
                                var newChildData = newRecord[childCNO.GetCNODataObjectTableAlias()];
                                var oldChildData = oldRecord[childCNO.GetCNODataObjectTableAlias()];
                                var newChildRecords = new List<TRecord>();
                                var oldChildRecords = new List<TRecord>();
                                //根据子节点与当前节点的关联关系处理
                                var relationtype = childCNO.GetRelationType();
                                if (relationtype == 0)
                                {
                                    if (newChildData != null && newChildData is List<TRecord> news)
                                    {
                                        newChildRecords.AddRange(news);
                                    }
                                    if (oldChildData != null && oldChildData is List<TRecord> olds)
                                    {
                                        oldChildRecords.AddRange(olds);
                                    }
                                }
                                else
                                {
                                    if (newChildData != null && newChildData is TRecord news)
                                    {
                                        newChildRecords.Add(news);
                                    }
                                    if (oldChildData != null && oldChildData is TRecord olds)
                                    {
                                        oldChildRecords.Add(olds);
                                    }
                                }

                                if ((newChildRecords != null && newChildRecords.Count > 0) || (oldChildRecords != null && oldChildRecords.Count > 0))
                                {
                                    //new old record集合都为空时跳过，然后填充空的new或者old Record，防止空引用
                                    //if (newChildRecords == null) newChildRecords = new List<TRecord>();
                                    //if (oldChildRecords == null) oldChildRecords = new List<TRecord>();

                                    GetUpdateChangeSet(childCNO, newChildRecords, oldChildRecords, out bool childChangedFlag, controlContext, newRecord, depth + 1);
                                    //子节点有变更时，记录变更
                                    if (childChangedFlag) currentPkChangedFlag = true;
                                }
                            }
                        }
                        if (currentPkChangedFlag)
                        {
                            newRecord.ChangeType = TRecordChangeType.Update;
                            isChanged = true;
                        }
                    }
                }
                if (addRecords != null && addRecords.Count > 0)
                {
                    //新增数据只有NewRecord中有，不需要做合并
                    isChanged = true;
                    GetCreateChangeSetRecursive(cno, addRecords, controlContext, depth);
                }
                if (dropRecords != null && dropRecords.Count > 0)
                {
                    //删除的数据需要归并到new Record中
                    isChanged = true;
                    var ele = cno.GetPKColumn();
                    dropRecords.ForEach(r =>
                    {
                        r.ChangeType = TRecordChangeType.Delete;
                        r.ChangeSet = new TChangeSet
                        {
                            BillID = r.PKColumnValue,
                            CDOID = cno.CompositeDataObjectID,
                            CDOCode = cno.CompositeDataObject?.Code,
                            ChangeType = TRecordChangeType.Delete,
                            PKColumnName = ele?.ColumnName,
                            PKColumnValue = r.PKColumnValue,
                            ModifyTime = DateTime.Now,
                            Modifier = UserUtil.GetCurrentUserID(),
                            ModifierName = UserUtil.GetCurrentUserName(),
                            TenantID = UserUtil.GetCurrentUserTenantId(),
                        };
                    });
                    var parentNodeRef = parentNewRecord[cno.GetCNODataObjectTableAlias()];
                    var relationtype = cno.GetRelationType();
                    if (relationtype == 0)
                    {
                        if (parentNodeRef == null) parentNodeRef = new List<TRecord>();
                        if (parentNodeRef is List<TRecord> parentNodeList)
                        {
                            parentNodeList.AddRange(dropRecords);
                        }
                    }
                    else
                    {
                        if (parentNodeRef == null) parentNodeRef = new TRecord();
                        if (parentNodeRef is TRecord parentNode)
                        {
                            parentNode = dropRecords?.FirstOrDefault();
                        }
                    }
                }
            }
            catch (Exception e)
            {
                throw new Exception($"Get ChangeLog failed, cdo:{cno.CompositeDataObjectID}, cno:{cno.ID}, msg:{e.Message}", e);
            }
        }
        #endregion

        #region 大数据变更日志方法
        /// <summary>
        /// 获取明细变更日志
        /// </summary>
        /// <param name="cno">CDO节点</param>
        /// <param name="newRecords">新纪录</param>
        /// <param name="oldRecords">旧纪录</param>
        /// <param name="depth">深度</param>
        /// <returns></returns>
        private List<DataChangeItem> GetBigDataUpdateChangeLog(CompositeNodeObject cno, List<TRecord> newRecords, List<TRecord> oldRecords, int depth = 0)
        {
            var pkEle = cno.GetPKElement();
            var pkColName = cno.GetPKColumn().ColumnName;
            List<DataChangeItem> dataChangeItems = new List<DataChangeItem>();
            var normalEle = cno.Elements.Where(e => e.ElementType == ElementType.Normal).ToList();
            //bool IsRecordChanged = false;                       //record是否有变更，主要是给二三级用

            List<TRecord> dropRecords = null;                   //需要drop的记录
            List<TRecord> addRecords = null;                    //需要add的记录
            List<object> needCompareRecordIdentifiers = null;   //需要比较的记录的主键

            InitRecord(newRecords, cno);
            InitRecord(oldRecords, cno);

            dropRecords = oldRecords?.Except(newRecords, recordPKComparer).ToList();            //一定要指定Comparer
            addRecords = newRecords.Except(oldRecords, recordPKComparer).ToList();              //一定要指定Comparer

            var needCompareRecords = oldRecords.Except(dropRecords, recordPKComparer)?.ToList();
            needCompareRecordIdentifiers = needCompareRecords?.Select(t => t.GetValue(pkColName)).ToList();

            if (needCompareRecordIdentifiers != null)
            {
                foreach (var pk in needCompareRecordIdentifiers)
                {
                    var newRecord = newRecords.FirstOrDefault(r => FieldCompare(r.GetValue(pkColName), pk, pkEle.DataType));
                    var oldRecord = oldRecords.FirstOrDefault(r => FieldCompare(r.GetValue(pkColName), pk, pkEle.DataType));
                    if (Compare(cno, newRecord, oldRecord, out List<DataChangeItem> changeItems, depth))
                    {
                        dataChangeItems.AddRange(changeItems);
                    }
                    //需要递归比较变更
                    if (cno.ChildCompositeNodeObjects != null)
                    {
                        foreach (var childCNO in cno.ChildCompositeNodeObjects)
                        {
                            var newChildRecords = (List<TRecord>)newRecord[childCNO.GetCNODataObjectTableAlias()];
                            var oldChildRecords = (List<TRecord>)oldRecord[childCNO.GetCNODataObjectTableAlias()];
                            if (newChildRecords != null && oldChildRecords != null)
                            {
                                //new old record集合都为空时跳过，然后填充空的new或者old Record，防止空引用
                                if (newChildRecords == null) newChildRecords = new List<TRecord>();
                                if (oldChildRecords == null) oldChildRecords = new List<TRecord>();

                                var childCNOChangeItems = GetBigDataUpdateChangeLog(childCNO, newChildRecords, oldChildRecords, depth + 1);
                                if (childCNOChangeItems != null)
                                {
                                    dataChangeItems.AddRange(childCNOChangeItems.Where(o => o != null));
                                }
                            }
                        }
                    }
                }
            }
            if (addRecords != null)
            {
                //新增变更执行新增逻辑的递归
                var createRecordChanges = GetBigDataCreateRecordChangeRecursive(cno, addRecords, depth);
                dataChangeItems.AddRange(createRecordChanges);
            }
            if (dropRecords != null)
            {
                var delRecordPKs = dropRecords.Select(r => r.GetValue(pkColName)).ToList();
                var delRecordChanges = GetBigDataDeleteRecordChange(cno, delRecordPKs);
                dataChangeItems.AddRange(delRecordChanges);
            }
            return dataChangeItems;
        }
        #endregion

        #region 通用变更日志方法
        /// <summary>
        /// 获取明细变更日志
        /// </summary>
        /// <param name="cno">CDO节点</param>
        /// <param name="newRecords">新纪录</param>
        /// <param name="oldRecords">旧纪录</param>
        /// <param name="depth">深度</param>
        /// <returns></returns>
        private List<TChangeLog> GetUpdateChangeLog(CompositeNodeObject cno, List<TRecord> newRecords, List<TRecord> oldRecords, out bool isChanged, int depth = 0)
        {
            isChanged = false;
            var pkEle = cno.GetPKElement();
            var pkColName = cno.GetPKColumn().ColumnName;
            List<TChangeLog> changeSets = new List<TChangeLog>();
            var normalEle = cno.Elements.Where(e => e.ElementType == ElementType.Normal).ToList();
            //bool IsRecordChanged = false;                       //record是否有变更，主要是给二三级用

            List<TRecord> dropRecords = null;                   //需要drop的记录
            List<TRecord> addRecords = null;                    //需要add的记录
            List<object> needCompareRecordIdentifiers = null;   //需要比较的记录的主键

            InitRecord(newRecords, cno);
            InitRecord(oldRecords, cno);

            dropRecords = oldRecords?.Except(newRecords, recordPKComparer).ToList();            //一定要指定Comparer
            addRecords = newRecords.Except(oldRecords, recordPKComparer).ToList();              //一定要指定Comparer

            var needCompareRecords = oldRecords.Except(dropRecords, recordPKComparer)?.ToList();
            needCompareRecordIdentifiers = needCompareRecords?.Select(t => t.GetValue(pkColName)).ToList();

            if (needCompareRecordIdentifiers != null)
            {
                foreach (var pk in needCompareRecordIdentifiers)
                {
                    var currentPkChangedFlag = false;
                    TChangeLog set = GetNewSet();
                    var newRecord = newRecords.FirstOrDefault(r => FieldCompare(r.GetValue(pkColName), pk, pkEle.DataType));
                    var oldRecord = oldRecords.FirstOrDefault(r => FieldCompare(r.GetValue(pkColName), pk, pkEle.DataType));
                    //比较当前节点字段变更
                    if (currentPkChangedFlag = Compare(cno, newRecord, oldRecord, out List<TChangeData> changeDataDetails, depth))
                    {
                        set.ChangeDatas = changeDataDetails;
                    }
                    List<TChangeData> childChangeDatas = new List<TChangeData>();
                    //需要递归比较变更
                    if (cno.ChildCompositeNodeObjects != null)
                    {
                        foreach (var childCNO in cno.ChildCompositeNodeObjects)
                        {
                            var realationType = childCNO.GetRelationType();
                            TChangeData childChangeData = new TChangeData
                            {
                                ChangeDataType = realationType == 0 ? ChangeDataType.List : ChangeDataType.Record,
                                ColumnCode = TUtil.GetPropertyName(childCNO.DataObjectTableAlias, realationType == 0),
                                ColumnName = childCNO?.DataObject.Name,
                                SortOrder = 999,
                            };

                            var newChildRecords = (List<TRecord>)newRecord[childCNO.GetCNODataObjectTableAlias()];
                            var oldChildRecords = (List<TRecord>)oldRecord[childCNO.GetCNODataObjectTableAlias()];
                            if (newChildRecords != null || oldChildRecords != null)
                            {
                                //new old record集合都为空时跳过，然后填充空的new或者old Record，防止空引用
                                if (newChildRecords == null) newChildRecords = new List<TRecord>();
                                if (oldChildRecords == null) oldChildRecords = new List<TRecord>();

                                var childCNOChangeItems = GetUpdateChangeLog(childCNO, newChildRecords, oldChildRecords, out bool childChangedFlag, depth + 1);
                                //子节点有变更时，记录变更
                                if (childChangedFlag) currentPkChangedFlag = true;
                                if (childCNOChangeItems != null && childCNOChangeItems.Count > 0)
                                {
                                    var childSets = childCNOChangeItems.Where(o => o != null).ToList();

                                    if (childChangeData.ChangeDataType == ChangeDataType.List)
                                    {
                                        childChangeData.List = childSets;
                                    }
                                    else if (childChangeData.ChangeDataType == ChangeDataType.Record)
                                    {
                                        childChangeData.Record = childSets.FirstOrDefault();
                                    }

                                    childChangeDatas.Add(childChangeData);
                                }
                            }
                        }
                    }
                    set.ChangeDatas.AddRange(childChangeDatas);
                    if (currentPkChangedFlag)
                    {
                        isChanged = true;
                        changeSets.Add(set);
                    }
                }
            }
            if (addRecords != null && addRecords.Count > 0)
            {
                isChanged = true;
                //新增变更执行新增逻辑的递归
                var createRecordChanges = GetCreateRecordChangeRecursive(cno, addRecords, depth);
                changeSets.AddRange(createRecordChanges);
                //changeDatas.AddRange(createRecordChanges);
            }
            if (dropRecords != null && dropRecords.Count > 0)
            {
                isChanged = true;
                var delRecordPKs = dropRecords.Select(r => r.GetValue(pkColName)).ToList();
                var delRecordChanges = GetDeleteRecordChange(cno, delRecordPKs);
                changeSets.AddRange(delRecordChanges);
            }
            return changeSets;
        }

        private TChangeLog GetNewSet()
        {
            TChangeLog changeSet = ChangeSetTemplate?.DACCloneChangeSet();
            changeSet.DataChangeType = TDataChangeType.Modify;
            if (changeSet == null)
            {
                throw new Exception(string.Format(CommonStringClassEngine.AbstractChangeLog_GetChangeSetTemplateFail));
                return default;
            }
            return changeSet;
        }
        #endregion


        /// <summary>
        /// 获取当前状态变更
        /// </summary>
        /// <param name="cdo"></param>
        /// <param name="oldRecord"></param>
        /// <param name="newRecord"></param>
        /// <returns></returns>
        public List<StateChangeLog> GetStateChanged(CompositeDataObject cdo, TRecord oldRecord, TRecord newRecord)
        {
            List<StateChangeLog> result = new List<StateChangeLog>();
            List<StateMachineMetadata> stateMachines = InitCDOStateMachine(cdo);
            foreach (var machine in stateMachines)
            {
                string stateColKey = machine.CDOColKey;
                try
                {
                    var oldState = int.Parse(oldRecord.GetValue(stateColKey).ToString());
                    var newState = int.Parse(newRecord.GetValue(stateColKey).ToString());
                    TState tOldState = machine.States.FirstOrDefault(s => s.Key == oldState);
                    TState tNewState = machine.States.FirstOrDefault(s => s.Key == newState);
                    if (oldState != newState)
                    {
                        result.Add(new StateChangeLog
                        {
                            StateMachineID = machine.ID,
                            StateMachineCode = machine.Code,
                            StateColKey = machine.CDOColKey,
                            OldStateCode = oldState.ToString(),
                            OldStateName = tOldState?.Name,
                            NewStateCode = newState.ToString(),
                            NewStateName = tNewState?.Name,
                        });
                    }
                }
                catch (Exception e)
                {
                    var oldRecordStr = TRecord.ToJson(oldRecord);
                    var newRecordStr = TRecord.ToJson(newRecord);
                    throw new FasException(DataAccessErrorCode.PlugIn.ChangeLog.Error, string.Format(CommonStringClassEngine.UpdateChangeLog_GetStateChanged, cdo.Code, machine.Code, stateColKey, oldRecordStr, newRecordStr), e);
                }
            }
            return result;
        }

        #region NestClass
        /// <summary>
        /// 状态变更日志类
        /// </summary>
        public class StateChangeLog
        {
            public string StateMachineID { get; set; }
            public string StateMachineCode { get; set; }
            public string StateColKey { get; set; }
            public string OldStateCode { get; set; }
            public string OldStateName { get; set; }
            public string NewStateCode { get; set; }
            public string NewStateName { get; set; }
        }
        #endregion
    }
}
